const Client = require("ssh2").Client;
const os = require('os');
const path = require('path');
const logger = require('../log').logger;

const pid = process.pid;

function getIPAdress(){
    let interfaces = os.networkInterfaces();
    for(let i in interfaces.en0){
        if(interfaces.en0[i].family === "IPv4"){
            return interfaces.en0[i].address;
        }
    }
    return '';
}

/**
 * 获取服务器信息
 * @param {*} request 
 */
function getServer(request){
    let server = {
        host: request.host,
        port: request.port || 22,
        username: request.username,
        password: request.password,
        tryKeyboard: true,  //需要输入密码
    }
    return server;
}

function getProcessList(str, username){
    let pList = [];
    str.split("\n").forEach(p => {
        if(p){
            let pInfo = p.trim().split(/\s+/);
            let cmd = pInfo[7];
            if(cmd !== "grep" && cmd !== "bash" && (!username || username === pInfo[0])){
                pList.push({
                    user: pInfo[0],
                    pid: pInfo[1],
                    ppid: pInfo[2],
                    cpu: pInfo[3],
                    time: pInfo[4],
                    tty: pInfo[5],
                    stime: pInfo[6],
                    command: cmd
                });
            }
        }
    })
    return pList;
}

/**
 * 建立远程ssh连接
 */
function createSSHConnect(client, server){
    return new Promise((resolve, reject) => {
        logger.info("ssh2 connect host: " + server.host);
        client.on('ready', () => {
            logger.info(`ssh2 connect ${server.host} successful.`);
            resolve();
        })
        .on("error", function(err){
            logger.info(`ssh2 connect ${server.host} error: `, err);
            reject(err);
        })
        .on("close", function(hadError){
            if(hadError){
                logger.info(`ssh2 ${server.host} encounter error: `, hadError);
            }
        })
        .on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => {
            finish([server.password]);
        })
        .connect(server);
    });
}

/**
 * 封装promise执行shell命令
 */
function shellCommand(client, command){
    return new Promise((resolve, reject) => {
        client.exec(command, (err, stream) =>{
            if(err){
                logger.info(`exec command: ${command} error: `, err);
                reject(err);
            }
            let data = [];
            stream.on('close', (result, signalName, didCoreDump, description) => {
                    let receiveMsg = data.toString();
                    if(result === 0){
                        logger.info(`exec command: ${command} successful.`, receiveMsg);
                        resolve(receiveMsg);
                    }else{
                        logger.info(`exec command: ${command} failed: `, receiveMsg);
                        reject({
                            message: receiveMsg
                        });
                    }
                })
                .on('data', (chunk) => {
                    data.push(chunk);
                });
        });    
    });
}

function execShell(client, command){
    return new Promise((resolve, reject) => {
        client.shell(function(error, stream){
            if(error){
                logger.error("ssh2 exec shell error: ", error);
                reject(error);
            }
            let data = [];
            stream.on('close', (result, signalName, didCoreDump, description) => {
                let receiveMsg = data.toString();
                if(result === 0){
                    logger.info(`exec command: ${command} successful.`, receiveMsg);
                    resolve(receiveMsg);
                }else{
                    logger.info(`exec command: ${command} failed: `, receiveMsg);
                    reject({
                        message: receiveMsg
                    });
                }
            }).on('data', chunk => {
                data.push(chunk);
            })
            stream.end('cd /www/server/tomcat/bin\npwd\nexit\n');
        });
    });
};

const commands = ["start", "clearcache", "clearcode"];
const mutilCommands = ["stop", "restart"];

/**
 * 远程执行服务器命令
 * @param {*} req 
 * @param {*} res 
 */
function execCommand(req, res){
    logger.info("ssh2 connect from : ", req.ip);
    let request = req.body;
    let signal = request.signal;
    let command = '';
    if(!signal){
        res.json({
            errCode: 'signal is required',
            errMsg: 'signal不能为空'
        });
        return;
    }
    let server = getServer(request);
    if(commands.indexOf(signal) > -1){
        if(signal === "start"){
            command = request.shellpath;
        }else if(signal === "clearcache" || signal === "clearcode"){
            if(!request.cachepath){
                res.json({
                    errCode: 'cachepath is required',
                    errMsg: '清除路径不能为空'
                });
                return;
            }
            command = `rm -rf ${request.cachepath}`;
        }
        let client = new Client();
        createSSHConnect(client, server)
            .then(() => {
                if(request.type == '1'){
                    return execShell(client, command);
                }else{
                    return shellCommand(client, command);
                }
            })
            .then(result => {
                res.json({
                    errCode: '000000',
                    errMsg: result,
                });
                client.end();
            })
            .catch((err) => {
                res.json({
                    errCode: 'C00001',
                    errMsg: err.message,
                });
                client.end();
            });
    }else if(mutilCommands.indexOf(signal) > -1){
        if(!request.grep){
            res.json({
                errCode: 'grep is required',
                errMsg: 'grep关键字不能为空'
            });
            return;
        }
        let client = new Client();
        let command = `ps -ef | grep ${request.grep}`;
        createSSHConnect(client, server)
            .then(() => shellCommand(client, command))
            .then((result) => {
                //查询进程信息
                let pList = getProcessList(result, request.username);
                if(pList.length > 1){
                    Promise.reject({
                        message: "grep关键字查询到多个进程"
                    });
                }else if(pList.length === 0){
                    return null;
                }else{
                    return pList[0];
                }
            })
            .then(p => {
                //kill进程
                if(p){
                    let command = `kill -9 ${p.pid}`;
                    return shellCommand(client, command);
                }
            })
            .then(result => {
                //启动进程
                if(signal === "restart"){
                    return shellCommand(client, request.shellpath);
                }
            })
            .then((result) => {
                res.json({
                    errCode: '000000'
                });
                client.end();
            })
            .catch((err) => {
                res.json({
                    errCode: 'C00001',
                    errMsg: err.message,
                });
                client.end();
            });
    }else if(signal === "testStatus"){  //查询运行状态
        let command = `ps -ef | grep ${request.grep}`;
        let client = new Client();
        createSSHConnect(client, server)
            .then(() => shellCommand(client, command))
            .then((result) => {
                let pList = getProcessList(result, request.username);
                if(pList.length > 0){
                    res.json({
                        errCode: '000000',
                        status: true,
                        id: request.id,
                    });
                }else{
                    res.json({
                        errCode: '000000',
                        status: false,
                        id: request.id,
                    });
                }
                client.end();
            })
            .catch((err) => {
                res.json({
                    errCode: 'C00001',
                    errMsg: err.message,
                    status: "unknow",
                    id: request.id,
                });
                client.end();
            });
    }else{
        res.json({
            errCode: 'C00002',
            errMsg: "未识别的命令",
        });
    }
}

module.exports = execCommand;
